﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Research.Kinect.Nui;
using System.Windows.Forms;
using System.Collections;
using System.Drawing;

namespace KinectAssistant
{
    class ImageMotionDetector : MotionDetector
    {
        private string picPath;

        private Runtime kinectNui;

        private ArrayList lhandtrack = new ArrayList();

        private ArrayList rhandtrack = new ArrayList();

        private int frameCount = 0;

        ImageView imageView;

        // Constructor
        public ImageMotionDetector(string pic)
        {
            picPath = pic;
            imageView = new ImageView();
            imageView.currentPic = picPath;
            imageView.Show();
        }

        private void InitializeNui()
        {
            try
            {
                kinectNui = new Runtime();

                //kinectNui.Initialize(RuntimeOptions.UseColor | RuntimeOptions.UseSkeletalTracking | RuntimeOptions.UseColor);
                kinectNui.Initialize(RuntimeOptions.UseSkeletalTracking);

                //kinectNui.VideoStream.Open(ImageStreamType.Video, 2, ImageResolution.Resolution640x480, ImageType.ColorYuv);

                kinectNui.SkeletonFrameReady += new EventHandler<SkeletonFrameReadyEventArgs>(SkeletonFrameReady);
            }
            catch (InvalidOperationException ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        public void Process()
        {
 
            InitializeNui();
        }

        void SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
        {
            foreach (SkeletonData data in e.SkeletonFrame.Skeletons)
            {
                if (SkeletonTrackingState.Tracked != data.TrackingState) continue;

                foreach (Joint joint in data.Joints)
                {
                    if (joint.Position.W < 0.6f) return;

                    frameCount++;

                    switch (joint.ID)
                    {

                        case JointID.HandRight:
                            rhandtrack.Add(joint);
                            break;
                        case JointID.HandLeft:
                            lhandtrack.Add(joint);
                            break;
                    }
                }
            }

            if (frameCount > 5)
            {
                Joint[] rhand = (Joint[])rhandtrack.ToArray(typeof(Joint));
                Joint[] lhand = (Joint[])lhandtrack.ToArray(typeof(Joint));

                string gesture = RecognizeMovement(lhand, rhand);

                if (gesture != "?")
                    ControlImage(gesture);

                rhandtrack.Clear();
                lhandtrack.Clear();

                frameCount = 0;
            }
        }

        private void ControlImage(string gesture)
        {
            switch (gesture)
            {
                case "MOVE":
                    float r1x, r1y, r2x, r2y;
                    int rlength = rhandtrack.Count;
                    r1x = ((Joint)rhandtrack[0]).Position.X;
                    r1y = ((Joint)rhandtrack[0]).Position.Y;
                    r2x = ((Joint)rhandtrack[rlength - 1]).Position.X;
                    r2y = ((Joint)rhandtrack[rlength - 1]).Position.Y;
                    Point offset = new Point((int)(r2x-r1x), (int)(r2y-r1y));
                    
                    imageView.moveImage(offset);
                    break;

                case "UP":
                    imageView.amplifyImage();
                    break;

                case "DOWN":
                    imageView.reduceImage();
                    break;
            }
        }

        private string RecognizeMovement(Joint[] lhand, Joint[] rhand)
        {
            float l1x, l1y, l2x, l2y;
            int llength = lhand.Length;
            l1x = lhand[0].Position.X;
            l1y = lhand[0].Position.Y;
            l2x = lhand[llength - 1].Position.X;
            l2y = lhand[llength - 1].Position.Y;

            float ldx = Math.Abs(l2x - l1x);
            float ldy = Math.Abs(l2y - l1y);

            float r1x, r1y, r2x, r2y;
            int rlength = rhand.Length;
            r1x = rhand[0].Position.X;
            r1y = rhand[0].Position.Y;
            r2x = rhand[rlength - 1].Position.X;
            r2y = rhand[rlength - 1].Position.Y;

            float rdx = Math.Abs(r2x - r1x);
            float rdy = Math.Abs(r2y - r1y);

            if (rdx > ldx && rdx < 1)
                return "MOVE";

            if (rdx > rdy)
            {
                if ((rdy == 0) || ((rdx / rdy) >= 2))
                {
                    if ((r2x - r1x > 0) && (l2x - l1x < 0))
                        return "UP";
                    else if ((r2x - r1x < 0) && (l2x - l1x > 0))
                        return "LEFT";
                    else
                        return "?";
                }
                else return "?";
            }
            else
                return "?";
        }
    }
}
